from decimal import Decimal
import json
from app.model.allocate_goods import AllocateGoods
from app.model.table_goods import TableGoods
from app.service import app_order
from app.service.goods import allocate_goods
from libs import common
from libs.db import DB


def get_goods_stock_amount(shop_id, goods_id):
    err = None
    stock_amount = 0
    try:
        goods_row = TableGoods.objects.filter(id=goods_id, shoper_id=shop_id).values('scount').get()
        stock_amount = goods_row.get('scount')
    except TableGoods.DoesNotExist:
        err = '商品不存在'
    if stock_amount == 0:
        err = '商品库存不足'
    return stock_amount, err


# 获取购物车内是否存在未结算的同一商品
def get_uncheck_cart(shop_id, cashier_id, cart_typ, goods_id, bill_num):
    db = DB('cs_carts')
    fields = ['id', 'amount', 'sig_barcode']
    where = {
        'shop_id': shop_id,
        'cashier_id': cashier_id,
        'goods_id': goods_id,
        'bill_num': bill_num,
        'cart_typ': cart_typ,
        'status': 0,
    }
    return db.one(fields, where)
# 获取购物车内是否存在未结算的同一商品（饮品）
def get_uncheck_cartdrink(shop_id, cashier_id, cart_typ, goods_id, bill_num,drink_type,drink_flavor):
    db = DB('cs_carts')
    fields = ['id', 'amount', 'sig_barcode']
    where = {
        'shop_id': shop_id,
        'cashier_id': cashier_id,
        'goods_id': goods_id,
        'bill_num': bill_num,
        'cart_typ': cart_typ,
        'status': 0,
        'drink_type':drink_type,
        'drink_flavor':drink_flavor,
    }
    return db.one(fields, where)
# 判断是否为json
def is_json(jsonstr):
    try:
        json_object = json.loads(jsonstr)
    except Exception as e:
        return False
    return True

# 购物车结算
def settlement(cursor, db_carts, goods_dict, app_order_data, stats_total_price_dec):
    now = common.get_ts()
    cs_order_id = app_order_data.get('cs_order_id')
    cs_order_sn = app_order_data.get('order_id')
    member_id = app_order_data.get('member_id')
    shop_name = app_order_data.get('shoper_name')
    order_time = app_order_data.get('order_time')
    pay_mode = app_order_data.get('pay_mode')
    only_pay_no = app_order_data.get('only_pay_no', '')
    send_shop_id = app_order_data.get('send_shop_id')
    pay_time = app_order_data.get('pay_time', '')
    state = app_order_data.get('state', 7)
    values_arr = []
    ver_counter_dict = {}
    action_code = 0
    err = None
    for cart in db_carts:
        cart_shop_id = cart.get('shop_id')
        cart_cashier_id = cart.get('cashier_id')
        cart_goods_id = cart.get('goods_id')
        cart_goods_id_str = str(cart_goods_id)
        cart_goods_name = cart.get('goods_name')
        cart_barcode = cart.get('barcode')
        cart_spec_typ = cart.get('spec_typ')
        drink_type = cart.get('drink_type')
        drink_type_str = str(drink_type)
        drink_flavor = cart.get('drink_flavor')
        remark = cart.get('remark')
        cart_is_half = cart.get('is_half')
        cart_is_half_str = str(cart_is_half)
        cart_goods_amount_dec = cart.get('amount')
        cart_half_num = int(cart_goods_amount_dec / 2)
        cart_half_num_str = str(cart_half_num)
        stock_prev = 0
        stock_next = 0
        cart_spec_typ_str = str(cart_spec_typ)
        cs_order_id_str = str(cs_order_id)
        cart_goods_is_discount = str(cart.get('is_discount'))
        cart_goods_is_input_price = str(cart.get('is_input_price'))
        cart_goods_amount_str = str(cart_goods_amount_dec)
        stock_log1 = {}
        stock_log2 = {}
        cart_subtotal_dec = cart.get('subtotal')
        if cart_goods_amount_dec == 0:
            cart_selling_price_dec = Decimal('0')
        else:
            if cart_is_half > 0:
                cart_selling_price = cart.get('selling_price')
                cart_selling_price_dec = cart_selling_price.quantize(Decimal('0.00'))
            else:
                cart_selling_price_dec = (cart_subtotal_dec / cart_goods_amount_dec).quantize(Decimal('0.00'))
        cart_selling_price_str = str(cart_selling_price_dec)
        cart_subtotal_str = str(cart.get('subtotal'))
        cart_subtotal_raw_str = str(cart.get('subtotal_raw'))
        s_now = str(now)
        db_goods_cost_price_dec = Decimal('0')
        if cart_goods_id > 0:  # 购物车商品有可能通过手工录入
            db_goods = goods_dict.get(cart_goods_id, None)
            if type(db_goods) is TableGoods:
                db_goods_cost_price_dec = common.to_dec(db_goods.cost_price)
                db_goods_ver = ver_counter_dict.get(cart_goods_id, db_goods.ver)
                db_goods_sell_count = db_goods.sell_count
                g_oinfo = DB('table_goods', conn=cursor).one(['scount'],{'id':cart_goods_id})
                stock_prev = g_oinfo.get('scount',0) #db_goods.scount
                stock_next = stock_prev - cart_goods_amount_dec
                new_goods_sell_count = db_goods_sell_count + cart_goods_amount_dec
                # 以下为库存组合拆分逻辑
                if stock_next < 0 and db_goods.assoc_goods_id >= 0:
                    # 商品库存不足，获取关联商品信息，看看能不能匀点过来
                    # 拆分组装，不应该导致创建订单失败。
                    # 如果拆分组装过程发生失败，记录原因，正常走之后的流程，不影响库存的扣除。
                    ag = AllocateGoods()
                    ag.id = db_goods.id
                    ag.assoc_goods_id = db_goods.assoc_goods_id
                    ag.pack_qty = db_goods.pack_qty
                    ag.need_amount = cart_goods_amount_dec -  stock_prev
                    ag_res = allocate_goods(ag)
                    ag_err = ag_res.get('err', '未知错误')
                    if ag_err is None:
                        assoc_goods = ag_res.get('assoc_goods', None)
                        if type(assoc_goods) is dict:
                            assoc_goods_id = assoc_goods.get('id', 0)
                            if assoc_goods_id > 0:
                                assoc_goods_stock_num = assoc_goods.get('scount', 0)
                                assoc_goods_cost_price = assoc_goods.get('cost_price', 0)
                                assoc_goods_ver = assoc_goods.get('ver', 0)
                                allocate_typ = ag_res.get('typ', '')
                                allocate_num = ag_res.get('allocate_num', 0)
                                to_unit_num = ag_res.get('to_unit_num', 0)
                                if allocate_typ == 'pack':
                                    #将关联商品打包成件出售
                                    assoc_goods_stock_surplus_num = assoc_goods_stock_num - allocate_num
                                    update_assoc_goods_sql = 'update table_goods set scount=%s,ver=%s' \
                                                             ' where id=%s and ver=%s'
                                    update_assoc_goods_bindings = [assoc_goods_stock_surplus_num,
                                                                   assoc_goods_ver + 1,
                                                                   assoc_goods_id,
                                                                   assoc_goods_ver]
                                    affected = cursor.execute(update_assoc_goods_sql,
                                                              update_assoc_goods_bindings)
                                    if affected == 1:
                                        stock_log1 = {
                                            'stock_order_id': 0,
                                            'stock_typ': 16,
                                            'goods_id': assoc_goods_id,
                                            'shop_id': cart_shop_id,
                                            'cashier_id': cart_cashier_id,
                                            'cash_device_code': '',
                                            'cost_price': assoc_goods_cost_price,
                                            'amount': str(allocate_num),
                                            'amount_prev': str(assoc_goods_stock_num),
                                            'amount_next': str(assoc_goods_stock_surplus_num),
                                            'created': now,
                                        }
                                        stock_log2 = {
                                            'stock_order_id': 0,
                                            'stock_typ': 16,
                                            'goods_id': cart_goods_id,
                                            'shop_id': cart_shop_id,
                                            'cashier_id': cart_cashier_id,
                                            'cash_device_code': '',
                                            'cost_price': db_goods_cost_price_dec,
                                            'amount': str(to_unit_num),
                                            'amount_prev': str(stock_prev),
                                            'amount_next': str(stock_prev + to_unit_num),
                                            'created': now,
                                        }
                                        stock_next = 0
                                        stock_prev = stock_prev + to_unit_num
                                elif allocate_typ == 'split':
                                    #将关联商品拆分成单件出售
                                    assoc_goods_stock_surplus_num = assoc_goods_stock_num - allocate_num
                                    update_assoc_goods_sql = 'update table_goods set scount=%s,ver=%s' \
                                                             ' where id=%s and ver=%s'
                                    update_assoc_goods_bindings = [assoc_goods_stock_surplus_num,
                                                                   assoc_goods_ver + 1,
                                                                   assoc_goods_id,
                                                                   assoc_goods_ver]
                                    affected = cursor.execute(update_assoc_goods_sql,
                                                              update_assoc_goods_bindings)
                                    if affected == 1:
                                        stock_log1 = {
                                            'stock_order_id': 0,
                                            'stock_typ': 15,
                                            'goods_id': assoc_goods_id,
                                            'shop_id': cart_shop_id,
                                            'cashier_id': cart_cashier_id,
                                            'cash_device_code': '',
                                            'cost_price': assoc_goods_cost_price,
                                            'amount': str(allocate_num),
                                            'amount_prev': str(assoc_goods_stock_num),
                                            'amount_next': str(assoc_goods_stock_surplus_num),
                                            'created': now,
                                        }
                                        stock_log2 = {
                                            'stock_order_id': 0,
                                            'stock_typ': 15,
                                            'goods_id': cart_goods_id,
                                            'shop_id': cart_shop_id,
                                            'cashier_id': cart_cashier_id,
                                            'cash_device_code': '',
                                            'cost_price': db_goods_cost_price_dec,
                                            'amount': str(to_unit_num),
                                            'amount_prev': str(stock_prev),
                                            'amount_next': str(stock_prev + to_unit_num),
                                            'created': now,
                                        }
                                        stock_next = stock_prev + to_unit_num - cart_goods_amount_dec
                                        stock_prev = stock_prev + to_unit_num
                    else:
                        print(ag_err)
                goods_dh = DB('table_goods', conn=cursor)
                affected, _ = goods_dh.update({
                    'scount': stock_next,
                    'sell_count': new_goods_sell_count,
                    'ver': db_goods_ver + 1,
                }, {'id': cart_goods_id, 'ver': db_goods_ver})
                if affected == 0:
                    action_code = 1
                    return values_arr, action_code, '更新商品库存失败'
                db_goods_ver += 1
                ver_counter_dict.update({cart_goods_id: db_goods_ver})
                goods_type = db_goods.is_fast_food
                if goods_type == 3:
                    # 套餐商品，要扣减套餐内商品库存
                    menu_desc = db_goods.menu_desc
                    if menu_desc:
                        check_json = is_json(menu_desc)
                        if check_json:
                            menu_arr = json.loads(menu_desc)
                            for item in menu_arr:
                                item_goodid = item["good_id"]
                                item_goodnum = common.to_dec(item["good_num"])
                                g_info = goods_dh.one(['scount','cost_price'],{'id':item_goodid})
                                g_oldnum = g_info.get('scount',0)
                                g_newnum = g_oldnum - item_goodnum
                                goods_dh.update({'scount':g_newnum},{'id':item_goodid})
                                item_log = {
                                    'stock_order_id': 0,
                                    'stock_typ': 2,
                                    'goods_id': item_goodid,
                                    'shop_id': cart_shop_id,
                                    'cashier_id': cart_cashier_id,
                                    'cash_device_code': '',
                                    'cost_price': common.to_dec(g_info.get('cost_price')),
                                    'amount': item_goodnum,
                                    'amount_prev': g_oldnum,
                                    'amount_next': g_newnum,
                                    'created': now,
                                }
                                DB('cs_stock_logs', conn=cursor).insert(item_log)
        stock_next_str = str(stock_next)
        stock_prev_str = str(stock_prev)
        stats_price_dec = Decimal(0)
        if stats_total_price_dec > 0:
            stats_price_dec = (Decimal(cart_subtotal_str) / stats_total_price_dec).quantize(Decimal('0.00'))
        app_order_detail_data = {
            'order_id': cs_order_sn,
            'goods_id': cart_goods_id_str,
            'member_id': member_id,
            'shoper_name': shop_name,
            'goods_name': cart_goods_name,
            'goods_price': cart_selling_price_str,
            'order_time': order_time,
            'ratio': 0,
            'sell_number': cart_goods_amount_str,
            'is_discount_goods': cart_goods_is_discount,
            'sell_price': cart_subtotal_str,
            'stats_price': str(stats_price_dec),
            'state': state,
            'pay_mode': pay_mode,
            'pay_usdt': cart_subtotal_str,
            'only_pay_no': only_pay_no,
            'send_shop_id': send_shop_id,
            'is_half': cart_is_half,
            'drink_type':drink_type,
            'drink_flavor':drink_flavor,
            'remark':remark
        }
        if pay_time != '':
            app_order_detail_data.update({'pay_time': pay_time})
        order_detail_id, err = app_order.save_app_order_detail(cursor, app_order_detail_data)
        if err is not None or order_detail_id == 0:
            action_code = 1
            return values_arr, action_code, '订单明细保存失败'

        if cart_goods_id > 0:
            stock_log_dh = DB('cs_stock_logs', conn=cursor)
            stock_log_data = {
                'stock_order_id': order_detail_id,
                'stock_typ': 2,
                'goods_id': cart_goods_id,
                'shop_id': cart_shop_id,
                'cashier_id': cart_cashier_id,
                'cash_device_code': '',
                'cost_price': db_goods_cost_price_dec,
                'amount': cart_goods_amount_str,
                'amount_prev': stock_prev_str,
                'amount_next': stock_next_str,
                'created': now,
            }
            stock_log_dh.insert(stock_log_data)
            if bool(stock_log1):
                stock_log_dh.insert(stock_log1)
            if bool(stock_log2):
                stock_log_dh.insert(stock_log2)
        drink_flavor_str = drink_flavor.replace('"', '\\"')
        value_arr = [cs_order_id_str, cart_goods_id_str, cart_goods_name, cart_barcode,
                     cart_goods_amount_str, cart_selling_price_str, cart_spec_typ_str, cart_goods_is_input_price,
                     cart_goods_is_discount, cart_subtotal_raw_str, cart_subtotal_str, cart_is_half_str,
                     cart_half_num_str, stock_prev_str, stock_next_str, s_now, s_now,drink_type_str,drink_flavor_str,remark]
        values_arr.append('("%s")' % '","'.join(value_arr))
    return values_arr, action_code, err


def query_return_goods_cart(cursor, shop_id, bill_num):
    fields = ['id', 'shop_id', 'cashier_id', 'barcode',
              'sig_barcode', 'goods_id', 'member_id', 'bill_num',
              'goods_name', 'selling_price', 'is_input_price', 'is_discount',
              'is_half', 'unit_price', 'amount', 'subtotal',
              'spec_typ', 'cart_typ', 'status', 'created']
    where = {
        'shop_id': shop_id,
        'bill_num': bill_num,
        'status': 0,
        'cart_typ in (1,2)': None,
    }
    db = DB('cs_carts', conn=cursor)
    return db.find(fields, where)


def pick_cart_goods(db_carts):
    cart_cat_dict = {}
    cart_total_amount = Decimal('0')
    for db_cart in db_carts:
        cart_typ = db_cart.get('cart_typ')
        subtotal_dec = db_cart.get('subtotal')
        cart_total_amount += subtotal_dec
        cart_cat_item = cart_cat_dict.get(cart_typ)
        if cart_cat_item is None:
            cart_cat_item = {
                'arr': [],
                'cart_total_price': Decimal('0'),
                'num': Decimal('0')
            }
        cart_cat_arr = cart_cat_item.get('arr')
        cart_cat_arr.append(db_cart)
        order_total_price = cart_cat_item.get('cart_total_price') + subtotal_dec
        cart_cat_item.update({'cart_total_price': order_total_price})
        order_goods_num = cart_cat_item.get('num') + db_cart.get('amount')
        cart_cat_item.update({'num': order_goods_num})
        cart_cat_dict.update({cart_typ: cart_cat_item})
    return cart_cat_dict, cart_total_amount


def get_cart_total_amount(db_carts):
    cart_total_amount = Decimal('0')
    order_goods_num = Decimal('0')
    cart_typ_set = set()
    for db_cart in db_carts:
        cart_typ = db_cart.get('cart_typ')
        subtotal_dec = db_cart.get('subtotal')
        cart_total_amount += subtotal_dec
        order_goods_num += abs(db_cart.get('amount'))
        cart_typ_set.add(cart_typ)
    return cart_total_amount, cart_typ_set, order_goods_num


def update_cart_status_by_bill_num(cursor, shop_id, bill_num):
    db = DB('cs_carts', conn=cursor)
    now = common.get_ts()
    new_cart_data = {
        'status': 1,
        'updated': now,
    }
    return db.update(new_cart_data, {
        'shop_id': shop_id,
        'bill_num': bill_num,
        'status': 0,
        'cart_typ in (1,2)': None,
    })
